package rabbitas{
	import flash.events.TextEvent;
	import rabbitas.flow.DiligentObjectInitFlow;
	import rabbitas.util.TextUtil;

	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.registerClassAlias;
	
	/**

	 * @author martindyrby
	 */
	[Event(name="complete", type="flash.events.Event")]
	[Event(name="ioError", type="flash.events.IOErrorEvent")]
	[Event(name="progress", type="flash.events.ProgressEvent")]
	public class RabbitAS extends EventDispatcher {
		
		static public const ERROR_LOG:uint = 0;
		static public const INFO_LOG:uint = 1;
		static public const DEBUG_LOG:uint=2;
		
		private var instanceManager:InstanceManager;
		private var propertyManager:PropertyManager;
		private var autoWireManager:AutoWireManager;
		
		private var xmlloader : URLLoader;

		public var ROOT:DisplayObject;
		private var liveCycleManager:LiveCycleManager;
		private var diligentObjectInitFlow:DiligentObjectInitFlow;

		public function RabbitAS(root:DisplayObject) {
			ROOT = root;
			
			registerClassAlias("text", TextUtil);
		}
		
		public function set logLevel(value:uint) : void {
			RabbitLogger.level = value;
		}

		public function init(xmlPath:String) : void {
			xmlloader = new URLLoader();
			xmlloader.addEventListener(Event.COMPLETE, onLoadComplete, false, 0, true);
			xmlloader.addEventListener(IOErrorEvent.IO_ERROR, onLoadIOErrorComplete, false, 0, true);
			xmlloader.addEventListener(ProgressEvent.PROGRESS, onLoadProgress, false, 0, true);
			xmlloader.load(new URLRequest(xmlPath));
		}

		public function getObjectById(id:String) : * {
			return instanceManager.getObjectById(id);
		}
		
		public function executeCommand(id:String, callback:Function = null, ...params) : IRabbitCommand {
			var cmd:IRabbitCommand = getObjectById(id);
			cmd.execute(callback, params);
			return cmd;
		}

		public function destroyObjectById(id:String) : void {
			instanceManager.destroyObjectById(id);			
		}
		
		public function resolveValue(expression:String):*{
			return Reflector.reflectStringValue(expression,instanceManager);
		}
		
		public function autowireInstance(instance:*):void{
			autoWireManager.autoWireInstance(instance);
		}
		
		// XML LOAD HANDLERS
		private function onLoadProgress(event : ProgressEvent) : void {
			RabbitLogger.debug("XML load progress:", event.bytesLoaded, "of", event.bytesTotal);
			dispatchEvent(event);
		}

		private function onLoadIOErrorComplete(event : IOErrorEvent) : void {
			RabbitLogger.error("XML load Error:", event);
			dispatchEvent(event);
		}

		private function onLoadComplete(event : Event) : void {
			RabbitLogger.info("XML load complete");
			var xmldata : XML = XML(xmlloader.data);
			instanceManager = new InstanceManager(xmldata, this);
			propertyManager = new PropertyManager(xmldata);
			autoWireManager = new AutoWireManager(xmldata);
			liveCycleManager = new LiveCycleManager();
		
			instanceManager.propertyManager=propertyManager;
			instanceManager.autoWireManager=autoWireManager;
			instanceManager.liveCycleManager=liveCycleManager;
			autoWireManager.instanceManager=propertyManager.instanceManager=instanceManager;
			
			instanceManager.init();
			propertyManager.resolveGlobalProperties();
			autoWireManager.resolveAutoWireDefinitions();

			diligentObjectInitFlow=new DiligentObjectInitFlow();
			diligentObjectInitFlow.init(instanceManager.instantiateDiligentObjects,onDiligentObjectsComplete,liveCycleManager,"initComplete");
			diligentObjectInitFlow.execute();
		}

		private function onDiligentObjectsComplete():void{
			diligentObjectInitFlow.destroy();
			diligentObjectInitFlow=null;
			instanceManager.resolveRootObject();
			
			dispatchEvent(new Event(Event.COMPLETE));
		}
	}
}
